processFile.js ➔ processText   D
last analyzed

Complexity

Conditions 10
Paths 2

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
nc 2
nop 3
dl 0
loc 42
rs 4.8196
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like processFile.js ➔ processText often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
const debug = require('debug')('mdprepare:processFile')
2
const {execSync} = require('child_process')
3
const fs = require('fs')
4
const os = require('os')
5
const path = require('path')
6
const h = require('./helpers.js')
7
const {findMdpCode} = require('./findMdpCode.js')
8
const {findMdpInsert} = require('./findMdpInsert.js')
9
10
export default function (filePath, clear) {
11
  // this function accepts a markdown filename and runs any mdprepare code which is embedded in that file
12
  debug(filePath)
13
  try {
14
    var txt = fs.readFileSync(filePath, 'utf8')
15
  } catch (err) {
16
    throw Error('file not found')
17
  }
18
  try {
19
    let p = processText(txt, clear, path.dirname(path.resolve(process.cwd(), filePath)))
20
    fs.writeFileSync(filePath, p)
21
  } catch (err) {
22
    throw Error('unable to write to file')
23
  }
24
  return true
25
}
26
27
export function processText (txt, clear, fileDirName) {
28
  let posn = 0
29
  let r = ''
30
  let x
31
  let y
32
  let t
33
  let frm
34
  let eolIsCRLF = (txt.indexOf('\r\n') !== -1)
35
  while (true) {
36
    x = findMdpCode(txt, posn)
37
    y = findMdpInsert(txt, posn)
38
    t = h.earlierOf(x, y)
39
    if (t.start === -1) {
40
      r = r + txt.substring(posn)
41
      break
42
    } else {
43
      r = r + txt.substring(posn, t.internalStart)
44
      frm = t.internalStart + t.internalLength
45
      analyseCommandString(t)
46
      if (t.info.cliCommand === 'ERROR: mdpInsert command not found') {
47
        // the mdpInsert command was not present so we don't insert or remove anything, just leave as is
48
        r = r + txt.substr(t.internalStart, t.internalLength)
49
      } else {
50
        if (clear !== true) {
51
          let insertText = t.prepend + runCliCmd(t.info.cliCommand, fileDirName)
52
          if (insertText.substr(-1) !== '\n' && t.postpend.length > 0) { insertText += '\n' }
53
          insertText += t.postpend
54
          r = r + h.replaceLineEndings(insertText, eolIsCRLF)
55
        }
56
        if (r.substr(-1) === '\n') {
57
          // we don't want to introduce 2 CRLFs or LFs so remove all lines between the start and end lines
58
          if (txt.substr(frm, 1) === '\r') { frm++ }
59
          /* istanbul ignore else  */
60
          if (txt.substr(frm, 1) === '\n') { frm++ }
61
        }
62
      }
63
      posn = t.start + t.length
64
      r = r + txt.substring(frm, posn)
65
    }
66
  }
67
  return r
68
}
69
70
function analyseCommandString (t) {
71
  // looks at the command string, checks it is a valid mdpInsert and populates .cli, .prepend and .postpend
72
  if (typeof t.info === 'undefined') { t.info = {} }
73
  let x = t.commandString.indexOf('mdpInsert ')
74
  if (x === -1) {
75
    t.info.cliCommand = 'ERROR: mdpInsert command not found'
76
    return
77
  }
78
  let regex = /mdpInsert ((`{3,}|~{3,})[^ ]*) /
79
  let regexResult = regex.exec(t.commandString)
80
  if (regexResult === null) {
81
    t.info.cliCommand = t.commandString.substr(x + 10)
82
    t.prepend = ''
83
    t.postpend = ''
84
  } else {
85
    t.info.cliCommand = t.commandString.substr(x + regexResult[0].length)
86
    t.prepend = regexResult[1] + '\n'
87
    t.postpend = regexResult[2]
88
  }
89
}
90
91
export function runCliCmd (str, wDirName) {
92
  // wDirName is either an absolute path or a relative path to the directory node was run from
93
  let cmd = crossPlatformCmds(str)
94
  try {
95
    return execSync(cmd, {cwd: wDirName})
96
  } catch (err) {
97
    return 'ERROR: ' + err.message
98
  }
99
}
100
101
function crossPlatformCmds (cmd) {
102
  // does limited cross platform translation of limited commands
103
  let r = cmd
104
  /* istanbul ignore if  */
105
  if (os.platform() === 'win32') {
106
    if (cmd.substr(0, 4) === 'cat ') {
107
      r = r.replace('cat ', 'type ')
108
      r = r.replace(/\//g, '\\')
109
    }
110
  }
111
  return r
112
}
113